#include "system.h" 

unsigned short xpos, ypos;
unsigned short *videoram;
unsigned short color;

unsigned char *memcpy(unsigned char *dest, const unsigned char *src, int count){
	int i;

	for (i = 0; i < count; i++)
		dest[i] = src[i];
	return dest;
}

unsigned char *memset(unsigned char *dest, unsigned char val, int count){
	int i;

	for (i = 0; i < count; i++)
		dest[i] = val;
	return dest;
}

unsigned short *memsetw(unsigned short *dest, unsigned short val, int count){
	int i;

	for (i = 0; i < count; i++)
		dest[i] = val;
	return dest;
}

int strlen(const char *str){
	int i;

	for (i = 0; *str != '\0'; i++, str++);
	return i;
}

int strcmp(const char * str1, const char *str2){
	int i = 0;
	/*While none of the string have ended and they are still equal */
	while ( (*str1 != '\0' || *str2 != '\0') && *str1 == *str2){
		str1++;
		str2++;
		i++;
	}
	/* If both strings have ended then they are equal*/
	if (*str1 == '\0' && *str2 == '\0')
		return 0;
	/* Otherwise if one of then has ended or the other has a different
	 * (bugger) character say where it is*/
	else if (*str2 == '\0' || *str1 > *str2)
		return i;
	else
		return -1*i;
}

unsigned char inportb (unsigned short _port){
	unsigned char rv;
	__asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port));
	return rv;
}

void outportb (unsigned short _port, unsigned char _data){
	__asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data));
}

/*************
 * Screen related functions
 * */

void move_csr(void)
{
	unsigned temp;

	temp = ypos * 80 + xpos;

	outportb(0x3D4, 14);
	outportb(0x3D5, temp >> 8);
	outportb(0x3D4, 15);
	outportb(0x3D5, temp);
}

void putc(const char c){
	/* backspace */
	if(c == 0x08)
	{
		if(xpos != 0) xpos--;
	}
	else if (c == '\n') {
		xpos = 0;
		ypos++;
	} 
	else if (c == '\t') {
		xpos = (xpos + 8) & ~(8 - 1);
		if (xpos >= 80){
			xpos -= 80;
			ypos++;
		}
	} 
	else if (c == '\r') {
		xpos = 0;
	}
	else if (c >= ' ')
	{
		videoram[ypos*80 + xpos] = (color << 8) | c;
		xpos++;
	}

	if (xpos >= 80) {
		xpos = 0;
		ypos++;
	}

	if (ypos >= 25)
		scroll_screen();

	move_csr();
}

void puts(const char *str){
	int i;
	int j = strlen(str);
	char c;
	for (i = 0; 
			i < j; 
			i++){ 
		c = str[i];
		putc(c);
	}
}

void puti(const int n){
	int t = n;
	if (t < 0){
		putc('-');
		t = t * -1;
	}

	/* If its less than 10 print the character*/
	if (t < 10)
		putc(t | 0x30);
	else{
		/* Else, print the first part and then the unit*/
		puti(t / 10);
		puti(t % 10);
	}
}

void cls(){
	int i;

	xpos = ypos = 0;
	for (i = 0; i < 25; i++)
		memsetw(videoram, ' ', 80);
}

void video_init(){
	videoram = (unsigned short *) 0xb8000;
	cls();
	color = 0x07;
}

void scroll_screen(){
	int i;
	unsigned char *video = (unsigned char *)videoram;

	for (i = 1; i < 25; i++)
		memcpy(&video[(i-1)*160], &video[i*160], 160);

	ypos = 24;
	memsetw(&videoram[ypos*80], ' ', 80);
}

void settextcolor(unsigned char forecolor, unsigned char backcolor){
	color = (backcolor << 4) | (forecolor & 0x0F);	
}

char getx(){
	return xpos;
}
char gety(){
	return ypos;
}

void gotoxy(char x, char y){
	if (x >= 0 && x < 80 && y >= 0 && y < 25){
		xpos = x;
		ypos = y;
		move_csr();
	}
}

